/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.aop.asm;

import cn.easyplatform.org.objectweb.asm.MethodVisitor;
import cn.easyplatform.org.objectweb.asm.Opcodes;
import cn.easyplatform.org.objectweb.asm.Type;

final class AsmHelper implements Opcodes {

	static boolean packagePrivateData(Type type, MethodVisitor mv) {
		if (type.equals(Type.BOOLEAN_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf",
					"(Z)Ljava/lang/Boolean;");
		} else if (type.equals(Type.BYTE_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf",
					"(B)Ljava/lang/Byte;");
		} else if (type.equals(Type.CHAR_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf",
					"(C)Ljava/lang/Character;");
		} else if (type.equals(Type.SHORT_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf",
					"(S)Ljava/lang/Short;");
		} else if (type.equals(Type.INT_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf",
					"(I)Ljava/lang/Integer;");
		} else if (type.equals(Type.LONG_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf",
					"(J)Ljava/lang/Long;");
		} else if (type.equals(Type.FLOAT_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf",
					"(F)Ljava/lang/Float;");
		} else if (type.equals(Type.DOUBLE_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf",
					"(D)Ljava/lang/Double;");
		} else {
			return false;
		}
		return true;
	}

	static void unpackagePrivateData(Type type, MethodVisitor mv) {
		if (type.equals(Type.BOOLEAN_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "cn/easyplatform/aop/asm/Helper",
					"valueOf", "(Ljava/lang/Boolean;)Z");
		} else if (type.equals(Type.BYTE_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "cn/easyplatform/aop/asm/Helper",
					"valueOf", "(Ljava/lang/Byte;)B");
		} else if (type.equals(Type.CHAR_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "cn/easyplatform/aop/asm/Helper",
					"valueOf", "(Ljava/lang/Character;)C");
		} else if (type.equals(Type.SHORT_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "cn/easyplatform/aop/asm/Helper",
					"valueOf", "(Ljava/lang/Short;)S");
		} else if (type.equals(Type.INT_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "cn/easyplatform/aop/asm/Helper",
					"valueOf", "(Ljava/lang/Integer;)I");
		} else if (type.equals(Type.LONG_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "cn/easyplatform/aop/asm/Helper",
					"valueOf", "(Ljava/lang/Long;)J");
		} else if (type.equals(Type.FLOAT_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "cn/easyplatform/aop/asm/Helper",
					"valueOf", "(Ljava/lang/Float;)F");
		} else if (type.equals(Type.DOUBLE_TYPE)) {
			mv.visitMethodInsn(INVOKESTATIC, "cn/easyplatform/aop/asm/Helper",
					"valueOf", "(Ljava/lang/Double;)D");
		}
	}

	static void checkCast(Type type, MethodVisitor mv) {
		if (type.getSort() == Type.ARRAY) {
			mv.visitTypeInsn(CHECKCAST, type.getDescriptor());
			return;
		}
		if (!type.equals(Type.getType(Object.class))) {
			if (type.getOpcode(IRETURN) != ARETURN) {
				checkCast2(type, mv);
				unpackagePrivateData(type, mv);
			} else {
				mv.visitTypeInsn(CHECKCAST,
						type.getClassName().replace('.', '/'));
			}
		}
	}

	static void checkCast2(Type type, MethodVisitor mv) {
		if (type.equals(Type.BOOLEAN_TYPE)) {
			mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
		} else if (type.equals(Type.BYTE_TYPE)) {
			mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
		} else if (type.equals(Type.CHAR_TYPE)) {
			mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
		} else if (type.equals(Type.SHORT_TYPE)) {
			mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
		} else if (type.equals(Type.INT_TYPE)) {
			mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
		} else if (type.equals(Type.LONG_TYPE)) {
			mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
		} else if (type.equals(Type.FLOAT_TYPE)) {
			mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
		} else if (type.equals(Type.DOUBLE_TYPE)) {
			mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
		}
	}
}
